package org.zoomdev.zoom.aop.impl;

import org.zoomdev.zoom.aop.Invoker;
import org.zoomdev.zoom.aop.MethodInvokerFactory;
import org.zoomdev.zoom.aop.ProxyObject;
import org.zoomdev.zoom.common.exceptions.ZoomException;
import org.zoomdev.zoom.common.utils.CachedClasses;

import java.lang.reflect.Method;
import java.util.Arrays;

public final class PartProxyObject implements ProxyObject<PartProxyObject.InvokeInfo> {


    private final Object target;

    private final Method[] methods;

    public PartProxyObject(Object target) {
        this.target = target;
        this.methods = CachedClasses.getPublicMethods(target.getClass());
    }

    @Override
    public InvokeInfo create(Class<?> interfaceOrAbstractClass, Object instance, Method method) {
        Method m = findMethod(method);
        if (m == null) {
            throw new ZoomException("PartObject: "+target.getClass().getName()+"中无法找到:" + method);
        }
        Invoker invoker = MethodInvokerFactory.FACTORY.create(m);

        return new InvokeInfo(target, invoker);
    }

    @Override
    public Object invoke(InvokeInfo config, Object[] args) throws Throwable {
        //调用的是原方法
        return config.invoke(args);
    }

    protected Method findMethod(Method method) {
        for (Method m : methods) {
            if (!m.getName().equals(method.getName())) {
                continue;
            }

            Class[] types = m.getParameterTypes();
            Class[] other = method.getParameterTypes();
            if (types.length != other.length) {
                continue;
            }

            if (Arrays.equals(types, other)) {
                return m;
            }
        }
        return null;
    }

    static final class InvokeInfo {

        final Object target;
        final Invoker method;

        InvokeInfo(Object target, Invoker method) {
            this.target = target;
            this.method = method;
        }

        public Object invoke(Object[] args) throws Throwable {
            return method.invoke(target, args);
        }
    }
}
